<?php
// +----------------------------------------------------------------------
// | 知识星球[基于ThinkPHP5开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2018-2019 abcblockchain.io
// +----------------------------------------------------------------------
// | 后台管理使用了HisiPHP
// +----------------------------------------------------------------------
// | Author: abcblockchain.io
// +----------------------------------------------------------------------
namespace app\admin\controller;

use think\Db;
use app\common\model\Exchange as exchangeModel;
use think\config;
use app\common\util\Bitcoin;
use app\common\model\Currency as currencyModel;
use think\Exception;
use Web3\Web3;
use Web3\Contract;

/**
 * 资金交易控制器
 * @package app\admin\controller
 */
class Trans extends Admin
{
    /**
     * 充值记录
     * @author
     * @return string|\think\response\Json
     * @throws \think\Exception
     */
    public function recharge()
    {
        if ($this->request->isAjax()) {
            $keyword = $this->request->param('keyword');
            $page = $this->request->param('page/d', 1);
            $limit = $this->request->param('limit/d', 20);
            $map = [];
            if ($keyword) {
                $map['u.mobile'] = array('like',"%$keyword%");
            }
            $map['ex.opt_type'] = 1;
            $data['data'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->where($map)->field('ex.*,c.currency_name,c.currency_mark,u.mobile,u.nick')->page($page)->limit($limit)->order('ex.ctime desc')->select();
            $data['count'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->where($map)->count('ex.id');
            $data['code'] = 0;
            return json($data);
        }
        return $this->fetch();
    }

    /**
     * 提现列表
     * @author
     * @return string|\think\response\Json
     * @throws \think\Exception
     */
    public function withdraw()
    {
        if ($this->request->isAjax()) {
            $keyword = $this->request->param('keyword');
            $page = $this->request->param('page/d', 1);
            $limit = $this->request->param('limit/d', 20);
            $map = [];
            if ($keyword) {
                $map['u.mobile'] = array('like',"%$keyword%");
            }
            $map['ex.opt_type'] = 2;
            $data['data'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->where($map)->field('ex.*,c.currency_name,c.currency_mark,u.mobile,u.nick')->page($page)->limit($limit)->order('ex.ctime desc')->select();
            $data['count'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->where($map)->count('ex.id');
            $data['code'] = 0;
            return json($data);
        }
        return $this->fetch();
    }

    /**
     * 审核提现
     * @author
     * @param int $id
     */
    public function checkWithdraw($id = 0)
    {
        if ($this->request->isGet() && $id > 0) {
            $exchangeInfo = exchangeModel::where('id', $id)->find();
            if ($exchangeInfo) {
                if ($exchangeInfo['status'] != '1') {
                    return $this->error("已操作过");
                } else {
                    if ($exchangeInfo['currency_id'] == 1) {
                        $txid = $this->usdtTransfer($exchangeInfo['to'], $exchangeInfo['number']);
                    } elseif ($exchangeInfo['currency_id'] == 2) {
                        $lastInfo = exchangeModel::field('txid,id,nonce,status')->where('currency_id', 2)->where('status', 4)->where('opt_type', 2)->order('chtime desc')->find();
                        if ($lastInfo && $lastInfo['status'] == '4' && $lastInfo['nonce'] == '0') {
                            $nonce = $this->getTransInfo($lastInfo['txid']);
                            if ($nonce) {
                                exchangeModel::where('id', $lastInfo['id'])->update(['nonce' => $nonce]);
                            } else {
                                $this->error("上笔审核未完成，不能审核");
                                exit;
                            }
                        }
                        $txid = $this->vnsTransfer($exchangeInfo['to'], $exchangeInfo['number']);
                    } else {
                        $txid = $this->tokenTransfer($exchangeInfo['currency_id'], $exchangeInfo['to'], $exchangeInfo['number']);
                    }
                    if ($txid) {
                        exchangeModel::where('id', $id)->update(['status' => '4', 'uptime' => time(), 'txid' => $txid, 'chtime' => time()]);
                        return $this->success("操作成功");
                    } else {
                        return $this->error("操作失败");
                    }
                }
            } else {
                return $this->error('提现不存在');
            }
        } else {
            return $this->error('操作错误');
        }
    }

    /**
     * 刷新提现
     * @author
     * @param int $id
     * @throws \think\Exception
     */
    public function refreshWithdraw($id = 0)
    {
        if ($this->request->isGet() && $id > 0) {
            $exchangeInfo = exchangeModel::where('id', $id)->find();
            if ($exchangeInfo) {
                if ($exchangeInfo['status'] == '4' && $exchangeInfo['txid']) {
                    if ($exchangeInfo['currency_id'] == 1) {
                        $checkTrans = $this->getUsdtInfo($exchangeInfo['txid']);
                        if ($checkTrans) {
                            if ($checkTrans['valid']) {
                                exchangeModel::where('id', $id)->update(['status' => '2', 'blocknum' => $checkTrans['block']]);
                            } else {
                                if ($checkTrans['block'] > 0) {
                                    Db::table('exchange')->where('id', $id)->update(['status' => 5]);
                                }
                            }
                        }
                    } else{
                        $checkTrans = $this->checkTransaction($exchangeInfo['txid']);
                        if ($checkTrans) {
                            if (substr($checkTrans->blockNumber, 0, 2) == '0x')
                                $blockNumber = base_convert(substr($checkTrans->blockNumber, 2), 16, 10);
                            if (substr($checkTrans->status, 0, 2) == '0x')
                                $status = base_convert(substr($checkTrans->status, 2), 16, 10);
                            if ($status > 0) {
                                exchangeModel::where('id', $id)->update(['status' => '2', 'blocknum' => $blockNumber]);
                            } else {
                                if ($blockNumber > 0) {
                                    Db::name('exchange')->where('id', $id)->update(['status' => 5]);
                                }
                            }
                        }
                    }
                }
                return $this->success('刷新成功');
            } else {
                return $this->error('提现不存在');
            }
        } else {
            return $this->error('操作错误');
        }
    }

    /**
     * 获取交易信息
     * @author
     * @param $txid
     * @return bool|string
     */
    public function getTransInfo($txid)
    {
        vendor('ethereum.ethereum');
        $rpcurl = Config::get('queue.rpc_ip');
        $rpcport = Config::get('queue.rpc_port');
        $eth = new \Ethereum($rpcurl, $rpcport);
        $transInfo = $eth->vns_getTransactionByHash($txid);
        if ($transInfo) {
            if (substr($transInfo->nonce, 0, 2) == '0x')
                $nonce = substr($transInfo->nonce, 2);
            $nonce = base_convert($nonce, 16, 10);
            return $nonce;
        } else {
            return false;
        }
    }

    /**
     * 检查交易状态
     * @author
     * @param $txid
     * @return bool
     */
    public function checkTransaction($txid)
    {
        vendor('ethereum.ethereum');
        $rpcurl = Config::get('queue.rpc_ip');
        $rpcport = Config::get('queue.rpc_port');
        $eth = new \Ethereum($rpcurl, $rpcport);
        //$eth = new \Ethereum('https://mainnet.infura.io/v3/815e4a4dbb4649c1aed5c52aecc72f6a','');
        $transInfo = $eth->vns_getTransactionReceipt($txid);
        if ($transInfo) {
            return $transInfo;
        } else {
            return false;
        }
    }

    /**
     * 发送VNS
     * @author
     * @param $to
     * @param $value
     * @param int $nonce
     * @param int $gas
     * @return mixed
     * @throws \ErrorException
     */
    public function vnsTransfer($to, $value, $nonce = 0, $gas = 0)
    {
        vendor("ethereum.ethereum");
        $from = Config::get('queue.eth_address');
        $rpcPwd = Config::get('queue.rpc_pwd');
        $eth = new \Ethereum(Config::get('queue.rpc_ip'), Config::get('queue.rpc_port'));
        $gasprice = $eth->vns_gasPrice();
        if (substr($gasprice, 0, 2) == '0x') {
            $tgasprice = base_convert(substr($gasprice, 2), 16, 10);
        } else {
            $tgasprice = $gasprice;
        }
        if ($tgasprice < 4000000000) {
            $tgasprice = 4000000000;
        }
        $nprice = calc($value, '1000000000000000000', 'mul');
        $gas = "0x" . base_convert("90000", 10, 16);
        $price = "0x" . base_convert($nprice, 10, 16);
        $tgasprice = "0x" . base_convert($tgasprice, 10, 16);
        $param = new \Ethereum_Transaction($from, $to, $gas, $tgasprice, $price);
        $eth->personal_unlockAccount($from, $rpcPwd, 30);
        $hash = $eth->vns_sendTransaction($param);
        $eth->personal_lockAccount($from);
        return $hash;
    }

    /**
     * USDT交易
     * @author
     * @param $to
     * @param $value
     * @return mixed
     */
    public function usdtTransfer($to, $value)
    {
        $bitcoin = new Bitcoin(Config::get('queue.btc_user'), Config::get('queue.btc_pwd'));
        $from = Config::get('queue.btc_address');
        $hash = $bitcoin->omni_send($from, $to, 1, $value);
        return $hash;
    }

    /**
     * 获取USDT交易
     * @author
     * @param $txid
     * @return bool
     */
    public function getUsdtInfo($txid)
    {
        $bitcoin = new Bitcoin(Config::get('queue.btc_user'), Config::get('queue.btc_pwd'));
        $transInfo = $bitcoin->omni_gettransaction($txid);
        if ($transInfo) {
            return $transInfo;
        } else {
            return false;
        }
    }

    /**
     * token转账
     * @author
     * @param $currencyId
     * @param $to
     * @param $value
     */
    public function tokenTransfer($currencyId, $to, $value)
    {
        $currencyModel = new currencyModel();
        $currencyInfo = $currencyModel->currencyInfo($currencyId);
        $contractAddress = $currencyInfo['contract_address'];
        $from = Config::get('queue.eth_address');
        $abi = Config::get('queue.abi');
        $web3 = new Web3(Config::get('queue.rpc_url'));
        $contract = new Contract($web3->provider, $abi);
        $personal = $web3->personal;
        $value = calc($value, '1000000000000000000', 'mul');
        $gasNeed = '0x' . base_convert(90000, 10, 16);
        $txhash = '';
        $personal->unlockAccount($from, Config::get('queue.rpc_pwd'), function ($err, $unlocked) use ($contract, $contractAddress, $from, $to, $value, $gasNeed, &$txhash) {
            if ($err !== null) {
            }
            if ($unlocked) {
                $contract->at($contractAddress)->send('transfer', $to, $value, [
                    'from' => $from,
                    'gas' => $gasNeed
                ], function ($err, $result) use ($contract, $from, $to, &$txhash) {
                    if ($err !== null) {
                    }
                    if ($result) {
                        $txhash = $result;
                    }
                });
            }
        });
        if ($txhash) {
            return $txhash;
        } else {
            return false;
        }
    }

    /**
     * 重发提现
     * @author
     * @param int $id
     */
    public function resend($id = 0){
        if ($this->request->isGet() && $id > 0) {
            $exchangeInfo = exchangeModel::where('id', $id)->find();
            if ($exchangeInfo) {
                if ($exchangeInfo['status'] != '5') {
                    return $this->error("已操作过");
                } else {
                    if ($exchangeInfo['currency_id'] == 1) {
                        $txid = $this->usdtTransfer($exchangeInfo['to'], $exchangeInfo['number']);
                    } elseif ($exchangeInfo['currency_id'] == 2) {
                        $lastInfo = exchangeModel::field('txid,id,nonce,status')->where('currency_id', 2)->where('status', 4)->where('opt_type', 2)->order('chtime desc')->find();
                        if ($lastInfo && $lastInfo['status'] == '4' && $lastInfo['nonce'] == '0') {
                            $nonce = $this->getTransInfo($lastInfo['txid']);
                            if ($nonce) {
                                exchangeModel::where('id', $lastInfo['id'])->update(['nonce' => $nonce]);
                            } else {
                                $this->error("上笔审核未完成，不能审核");
                                exit;
                            }
                        }
                        $txid = $this->vnsTransfer($exchangeInfo['to'], $exchangeInfo['number']);
                    } else {
                        $txid = $this->tokenTransfer($exchangeInfo['currency_id'], $exchangeInfo['to'], $exchangeInfo['number']);
                    }
                    if ($txid) {
                        exchangeModel::where('id', $id)->update(['status' => '4', 'uptime' => time(), 'txid' => $txid, 'chtime' => time()]);
                        return $this->success("操作成功");
                    } else {
                        return $this->error("操作失败");
                    }
                }
            } else {
                return $this->error('提现不存在');
            }
        } else {
            return $this->error('操作错误');
        }
    }

    /**
     * 驳回提现申请
     * @author
     * @param int $id
     */
    public function toBack($id = 0){
        if ($this->request->isGet() && $id > 0) {
            $exchangeInfo = exchangeModel::where('id', $id)->find();
            if($exchangeInfo['status'] == '1' || $exchangeInfo['status'] == '5'){
                $number = $exchangeInfo['number'];
                $fee = $exchangeInfo['fee'];
                $uid = $exchangeInfo['uid'];
                $currencyId = $exchangeInfo['currency_id'];
                $returnToken = $number + $fee;
                $map = [];
                $map['user_id'] = $uid;
                $map['currency_id'] = $currencyId;
                Db::startTrans();
                try{
                    Db::name('users_currency')->where($map)->setInc('num', $returnToken);
                    Db::name('exchange')->where('id',$id)->update(['status' => 3]);
                    Db::commit();
                }catch(\Exception $e){
                    Db::rollback();
                    return $this->error('操作错误');
                }
                return $this->success("操作成功");
            }else{
                return $this->error("无法操作");
            }
        } else {
            return $this->error('操作错误');
        }
    }


    /**
     * 消费记录
     * @author
     * @return string|\think\response\Json
     * @throws Exception
     */
    public function consume(){
        if ($this->request->isAjax()) {
            $keyword = $this->request->param('keyword');
            $page = $this->request->param('page/d', 1);
            $limit = $this->request->param('limit/d', 20);
            $map = [];
            if ($keyword) {
                $map['u.mobile'] = array('like',"%$keyword%");
            }
            $map['ex.opt_type'] = array('in','6,7');
            $data['data'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->join('group g', 'ex.group_id=g.id', 'LEFT')->where($map)->field('ex.*,c.currency_name,c.currency_mark,u.mobile,u.nick,g.name')->page($page)->limit($limit)->order('ex.ctime desc')->select();
            $data['count'] = exchangeModel::alias('ex')->join('currency c', 'ex.currency_id = c.id')->join('users u', 'ex.uid = u.id')->where($map)->count('ex.id');
            $data['code'] = 0;
            return json($data);
        }
        return $this->fetch();
    }

}
